using Engine;
using Engine.Graphics;
using Game;
using GameEntitySystem;

namespace SCIENEW {
    public class CupronickelPipeDevice : DefaultDevice, IFluidTransferrerPipeDevice {

        public BlockMesh m_centerMesh = new();

        public BlockMesh[] m_aroundMeshes = new BlockMesh[6];

        public BlockMesh[] m_edgeMeshes = new BlockMesh[6];

        public BlockMesh m_standaloneBlockMesh = new();

        public CupronickelPipeDevice() : base( "CupronickelPipeDevice") {
            Model model = ContentManager.Get<Model>("Models/Pipe");
            Matrix boneAbsoluteTransform = BlockMesh.GetBoneAbsoluteTransform(model.FindMesh("Pipe_Center").ParentBone);
            m_centerMesh.AppendModelMeshPart(model.FindMesh("Pipe_Center").MeshParts[0], boneAbsoluteTransform * Matrix.CreateTranslation(0.5f, 0f, 0.5f), makeEmissive: false, flipWindingOrder: false, doubleSided: false, flipNormals: false, Color.White);
            for (int i = 0; i < 6; i++) {
                m_aroundMeshes[i] = new BlockMesh();
                boneAbsoluteTransform = BlockMesh.GetBoneAbsoluteTransform(model.FindMesh("Pipe_Normal_" + i).ParentBone);
                m_aroundMeshes[i].AppendModelMeshPart(model.FindMesh("Pipe_Normal_" + i).MeshParts[0], boneAbsoluteTransform * Matrix.CreateTranslation(0.5f, 0f, 0.5f), makeEmissive: false, flipWindingOrder: false, doubleSided: false, flipNormals: false, Color.White);

                m_edgeMeshes[i] = new BlockMesh();
                boneAbsoluteTransform = BlockMesh.GetBoneAbsoluteTransform(model.FindMesh("Pipe_Edge_" + i).ParentBone);
                m_edgeMeshes[i].AppendModelMeshPart(model.FindMesh("Pipe_Edge_" + i).MeshParts[0], boneAbsoluteTransform * Matrix.CreateTranslation(0.5f, 0f, 0.5f), makeEmissive: false, flipWindingOrder: false, doubleSided: false, flipNormals: false, Color.White);
            }

            m_standaloneBlockMesh.AppendBlockMesh(m_centerMesh);
            m_standaloneBlockMesh.AppendBlockMesh(m_edgeMeshes[1]);
            m_standaloneBlockMesh.AppendBlockMesh(m_edgeMeshes[3]);
            m_standaloneBlockMesh.TransformPositions(Matrix.CreateTranslation(-0.5f, -0.5f, -0.5f));
        }

        public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z) {
            //先绘制中心
            generator.GenerateShadedMeshVertices(
                BlocksManager.Blocks[BaseDeviceBlock.Index],
                x,
                y,
                z,
                m_centerMesh,
                Color.White,
                null,
                null,
                geometry.GetGeometry(IndustrialModLoader.IETexture).SubsetAlphaTest
            );
            //再绘制四周
            SubsystemTerrain subsystemTerrain = generator.SubsystemTerrain;
            SubsystemFluidTransfer subsystemFluidTransfer = subsystemTerrain.Project.FindSubsystem<SubsystemFluidTransfer>(true);
            List<int> connectedFace = new();
            for (int i = 0; i < 6; i++) {
                Point3 faceToPoint = CellFace.FaceToPoint3(i);
                int blockValue = subsystemTerrain.Terrain.GetCellValueFast(x + faceToPoint.X, y + faceToPoint.Y, z + faceToPoint.Z);
                if (Terrain.ExtractContents(blockValue) is BaseDeviceBlock.Index) {
                    DeviceBlock deviceBlock = DevicesBlockManager.GetDevice(blockValue);
                    if (deviceBlock is CupronickelPipeDevice) {
                        connectedFace.Add(i);
                        generator.GenerateShadedMeshVertices(
                            BlocksManager.Blocks[BaseDeviceBlock.Index],
                            x,
                            y,
                            z,
                            m_aroundMeshes[i],
                            Color.White,
                            null,
                            null,
                            geometry.GetGeometry(IndustrialModLoader.IETexture).SubsetAlphaTest
                        );
                    }
                    else if (deviceBlock is IFluidTransferrerDevice fluidTransferrerDevice && fluidTransferrerDevice.GetConnector(subsystemTerrain, blockValue, CellFace.OppositeFace(i), x + faceToPoint.X, y + faceToPoint.Y, z + faceToPoint.Z) != null) {
                        connectedFace.Add(i);
                        generator.GenerateShadedMeshVertices(
                            BlocksManager.Blocks[BaseDeviceBlock.Index],
                            x,
                            y,
                            z,
                            m_edgeMeshes[i],
                            Color.White,
                            null,
                            null,
                            geometry.GetGeometry(IndustrialModLoader.IETexture).SubsetAlphaTest
                        );
                    }
                }
            }
            //四周没有，绘制默认
            if (connectedFace.Count == 0) {
                generator.GenerateShadedMeshVertices(
                    BlocksManager.Blocks[BaseDeviceBlock.Index],
                    x,
                    y,
                    z,
                    m_edgeMeshes[1],
                    Color.White,
                    null,
                    null,
                    geometry.GetGeometry(IndustrialModLoader.IETexture).SubsetAlphaTest
                );
                generator.GenerateShadedMeshVertices(
                    BlocksManager.Blocks[BaseDeviceBlock.Index],
                    x,
                    y,
                    z,
                    m_edgeMeshes[3],
                    Color.White,
                    null,
                    null,
                    geometry.GetGeometry(IndustrialModLoader.IETexture).SubsetAlphaTest
                );
            }
            else if (connectedFace.Count == 1) {
                generator.GenerateShadedMeshVertices(
                    BlocksManager.Blocks[BaseDeviceBlock.Index],
                    x,
                    y,
                    z,
                    m_edgeMeshes[CellFace.OppositeFace(connectedFace[0])],
                    Color.White,
                    null,
                    null,
                    geometry.GetGeometry(IndustrialModLoader.IETexture).SubsetAlphaTest
                );
            }
        }

        public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData) {
            BlocksManager.DrawMeshBlock(
                primitivesRenderer,
                m_standaloneBlockMesh,
                IndustrialModLoader.IETexture,
                color,
                size,
                ref matrix,
                environmentData
            );
        }

        public override int GetDisplayOrder(int value) => base.GetDisplayOrder(value) + 1;

        public override bool IsTransparent_(int value) => true;

        public override bool IsFaceTransparent(SubsystemTerrain subsystemTerrain, int face, int value) => true;

        public override int GetShadowStrength(int value) => 0;

        public override float GetObjectShadowStrength(int value) => 0;

        public override int GetFaceTextureSlot(int face, int value) => 107;

        public override int GetMaxStacking(int value) => 40;

        public override DeviceBehavior[] GetBehaviors(Project project) => [new FluidPipeDeviceBehavior(project)];

        public Type GetTransferringFluidType() => typeof(IPipeableFluid);

        public HashSet<int> GetFaceMask(int value) => [0, 1, 2, 3, 4, 5];

        public PipeFluidConnection GetConnection(HashSet<FluidTransferrer> fromTransferrers, HashSet<FluidTransferrer> toTransferrers, HashSet<FluidConnector> fromConnectors, HashSet<FluidConnector> toConnectors, float rate, Type transferringType, SubsystemFluidTransfer subsystemFluidTransfer) => new(fromTransferrers, toTransferrers, fromConnectors, toConnectors, rate, transferringType, subsystemFluidTransfer);
    }
}